namespace sight {

    const effectShadow = false

    export class Sight {
        public EyeLocaion: utils.Vec2D
        private Points = new Array<utils.Vec2D>()
        private Shadows = new Array<utils.Polygon>()
        private Lines = new Array<utils.Line>()

        constructor() {
            this.EyeLocaion = new utils.Vec2D(0, 0)
        }

        public Draw(container: egret.DisplayObjectContainer) {
            this.Points.forEach((p) => {
                //container.addChild(p.Draw())
            })
            this.Shadows.forEach((p) => {
                container.addChild(p.Draw())
            })
            this.Lines.forEach((p) => {
                //container.addChild(p.Draw())
            })
            this.EyeLocaion.Erase()
            container.addChild(this.EyeLocaion.Draw())
        }

        public SetLoc(x, y: number) {
            this.EyeLocaion.SetLoc(x, y)
        }

        public MakeShadow(border: utils.Polygon, stones: Array<utils.Polygon>) {
            this.Points.forEach((p) => { p.Erase() })
            this.Points = new Array<utils.Vec2D>()

            this.Shadows.forEach((p) => { p.Erase() })
            this.Shadows = new Array<utils.Polygon>()

            this.Lines.forEach((line) => { line.Erase() })
            this.Lines = new Array<utils.Line>()

            //分别计算每个石头的阴影
            stones.forEach((poly) => {
                //对一个多边形所有定点的连线
                let lines = new Array<utils.Line>()
                poly.Points.forEach((point) => {
                    lines.push(new utils.Line(this.EyeLocaion, point))
                })

                //过滤被遮挡的点
                if (true) {
                    let tmp = this.linesWithoutCross(lines, poly)
                    if (effectShadow) {
                        stones.forEach((p) => { lines = this.linesWithoutCross(lines, p) })
                        if (lines.length == 0) {
                            return
                        } else {
                            lines = tmp
                        }
                    } else {
                        lines = tmp
                    }
                }
                this.Lines = this.Lines.concat(lines)

                //计算与边框的交点
                let hideLines = new Array<utils.Line>()
                lines.forEach((line) => {
                    border.Edges.forEach((edge) => {
                        let p = line.Cross(edge, true, false, true)
                        if (p) {
                            this.Points.push(p)
                            this.Points.push(line.To)
                            let l = new utils.Line(line.To, p)
                            l.Kind = utils.HideLine
                            hideLines.push(l)
                        }
                    })
                })

                //过滤被遮挡的点
                {
                    //hideLines = this.linesWithoutCross(hideLines, poly)
                }
                {
                    let p1 = new Array<utils.Vec2D>()
                    hideLines.forEach((line) => {
                        line.From.Kind = utils.ShadowPoint
                        p1.push(line.From)
                        line.To.Kind = utils.ShadowPoint
                        p1.push(line.To)
                    })
                    this.Points = this.Points.concat(p1)
                    let shadows = new utils.Polygon(utils.ShadowPolygon)
                    shadows.SetPoints(this.sortPointWithBorder(border, p1))
                    this.Shadows.push(shadows)
                }

                hideLines = this.linesWithoutCross(hideLines, poly)
                this.Lines = this.Lines.concat(hideLines)
            })
        }
        private linesWithoutCross(lines: Array<utils.Line>, poly: utils.Polygon): Array<utils.Line> {
            let tmpLines = new Array<utils.Line>()
            lines.forEach((line) => {
                let noCross = true
                poly.Edges.forEach((edge) => {
                    if (edge.OnLine(line.To) || edge.OnLine(line.From)) {
                        return
                    }
                    let p = line.Cross(edge, true, true, true)
                    if (p) {
                        //this.Points.push(p)
                        noCross = false
                    }
                })
                if (noCross) {
                    tmpLines.push(line)
                }
            })
            return tmpLines
        }
        private sortPointWithBorder(border: utils.Polygon, points: Array<utils.Vec2D>): Array<utils.Vec2D> {
            let c = new utils.Vec2D(0, 0)
            points.forEach((p) => {
                c.x += p.x
                c.y += p.y
            })
            c.x = c.x / points.length
            c.y = c.y / points.length

            let list = new Array<utils.Vec2D>()
            let tmp = new Array<any>()
            {
                points.forEach((p) => {
                    tmp.push({
                        Val: p,
                        Score: utils.SubVec2(c, p).Atan2()
                    })
                })
            }

            //插入Border的4个顶点
            {
                tmp = tmp.sort(function (a: any, b: any): number { return a.Score - b.Score })

                let lastPoint = tmp[tmp.length - 1].Val
                tmp.forEach((o) => {
                    let l1 = new utils.Line(lastPoint, o.Val)
                    border.Points.forEach((p) => {
                        let l2 = new utils.Line(this.EyeLocaion, p)
                        if (l2.Cross(l1, true, true, true)) {
                            tmp.push({
                                Val: p,
                                Score: utils.SubVec2(c, p).Atan2(),
                            })
                        }
                    })
                })
                border.Points.forEach((p) => {
                    let l2 = new utils.Line(this.EyeLocaion, p)
                    let cross = false
                    tmp.forEach((o) => {
                        let l1 = new utils.Line(lastPoint, o.Val)
                        if (l2.Cross(l1, true, true, true)) {
                            cross = true
                        }
                    })
                    if (cross) {
                        tmp.push({
                            Val: p,
                            Score: utils.SubVec2(c, p).Atan2(),
                        })
                    }
                })
            }

            tmp = tmp.sort(function (a: any, b: any): number { return a.Score - b.Score })

            tmp.forEach((o) => {
                list.push(o.Val)
            })

            return list
        }
    }

    export class MapProxy extends hjc.Proxy {
        public static Instance: MapProxy
        constructor() {
            super()
            MapProxy.Instance = this

            this.Border = new utils.Polygon(
                utils.Border,
                new utils.Vec2D(50, 50),
                new utils.Vec2D(650, 50),
                new utils.Vec2D(650, 1050),
                new utils.Vec2D(50, 1050),
            )

            this.Stones.push(
                new utils.Polygon(
                    utils.Stone,
                    new utils.Vec2D(131, 176),
                    new utils.Vec2D(216, 141),
                    new utils.Vec2D(290, 174),
                    new utils.Vec2D(273, 279),
                    new utils.Vec2D(154, 279),
                ),
                new utils.Polygon(
                    utils.Stone,
                    new utils.Vec2D(503, 220),
                    new utils.Vec2D(569, 289),
                    new utils.Vec2D(462, 379),
                ),
                new utils.Polygon(
                    utils.Stone,
                    new utils.Vec2D(194, 579),
                    new utils.Vec2D(264, 642),
                    new utils.Vec2D(236, 757),
                    new utils.Vec2D(90, 802),
                    new utils.Vec2D(91, 679),
                ),
                new utils.Polygon(
                    utils.Stone,
                    new utils.Vec2D(556, 591),
                    new utils.Vec2D(612, 745),
                    new utils.Vec2D(486, 885),
                ),
                new utils.Polygon(
                    utils.Stone,
                    new utils.Vec2D(299, 846),
                    new utils.Vec2D(344, 919),
                    new utils.Vec2D(400, 853),
                    new utils.Vec2D(442, 998),
                    new utils.Vec2D(216, 969),
                ),
            )
        }
        public Border: utils.Polygon
        public Stones = new Array<utils.Polygon>()
        public EyeLocaion = new Array<Sight>()

        public Lines = new Array<utils.Line>()
        public Points = new Array<utils.Vec2D>()
        public Shadows = new Array<utils.Polygon>()

        public UpdataEyeLocation(x, y: number) {
            if (effectShadow) {
                if (this.EyeLocaion.length == 0) {
                    this.EyeLocaion.push(new Sight())
                }
                this.EyeLocaion[0].SetLoc(x, y)
                this.EyeLocaion[0].MakeShadow(this.Border, this.Stones)
            } else {
                if (this.EyeLocaion.length == 0) {
                    this.EyeLocaion.push(new Sight())
                    this.EyeLocaion.push(new Sight())
                    this.EyeLocaion.push(new Sight())
                    this.EyeLocaion.push(new Sight())
                }
                let delta = 25
                this.EyeLocaion[0].SetLoc(x - delta, y)
                this.EyeLocaion[0].MakeShadow(this.Border, this.Stones)

                this.EyeLocaion[1].SetLoc(x + delta, y)
                this.EyeLocaion[1].MakeShadow(this.Border, this.Stones)

                this.EyeLocaion[2].SetLoc(x, y - delta)
                this.EyeLocaion[2].MakeShadow(this.Border, this.Stones)

                this.EyeLocaion[3].SetLoc(x, y + delta)
                this.EyeLocaion[3].MakeShadow(this.Border, this.Stones)
            }
            game.notify(sight.ntf.UpdateMap)
        }
    }

}